home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Merciful 2
/
Merciful - Disc 2.iso
/
software
/
a
/
alliancedoc's03.dms
/
alliancedoc's03.adf
/
CHAP5_5.doc.pp
/
CHAP5_5.doc
Wrap
Text File
|
1992-02-22
|
50KB
|
1,516 lines
________________________________________________________________________
/ \
| ALLIANCE Presents : Amiga Graphics Inside and Out. |
| The complete Book from Abacus. |
| |
| Typed By : Razor Blade. |
| Supplied By : Viper. |
| |
| ALLIANCE ARE : Alchemist, Aramis, Barbarian, CI/\RS, Chaos, Glitch, Mit, |
| Raistlin, Razor Blade, ShadowFax and Viper. |
| |
\________________________________________________________________________/
/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\
> <
> CALL OUR WORLD HQ N-O-W : UNKNOWN PLEASURES : +44 823 322891 <
> <
\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//
5.5 DESIGNING YOUR OWN FONTS.
By now you should know enough about the standard Amiga fonts. We will now
move onto the last and most difficult section: defining a completely
original font.
In order to do this you need to know about the contruction of a font. At
the beginning of this chapter we introduced you to the data structure named
TextFont. Before continuing with this data structure, we will present some
of the peculiarities of an Amiga font.
Basically, there are two different font forms for the Amiga:
a.) Normal fonts.
b.) Proportional fonts.
A typical font consists of characters that have equal height and width.
Proportional font characters also have equal heights but inidividual
widths.
You need a maximum of 4 memory blocks to define a font.
charData
charLoc
charSpace
charKern
charData contains the actual definition of a character in the font. This
refers to the bitpacked character information. Since an Amiga character can
be any character width that you select, it is wastful to store the data
for every character in byte form. Th Amiga stores the characters data as
follows:
Let's start with the two characters below. A "." represents an unset pixel
and a "*" represents a set pixel.
....*.... ****.
...*.*... *...*
..*...*.. *...*
.*.....*. ****.
********* *...*
*.......* *...*
* * ****
PAGE 234
-----------------------------------------------------------------------------
These two characters have different widths and could be from a proportional
font. The Amiga creates a bit-row, one after the other of all the characters
in a font. If our font contained only the characters above then charData
would look like this:
1. row: ....*....****.
2. row: ...*.*...*...*
3. row: ..*...*..*...*
4. row: .*.....*.****.
5. row: **********...*
6. row: *.......**...*
7. row: *.......*****.
The individual rows are then written one after the other into the memory
block:
charData: ....*....****....*.*...*...*..*...*..*...* etc ...
This storage methoid is very efficient but has one problem. We need to
get the characters out of the bits. This is why there is a memory block,
call charLoc. This block contains two words (two-byte fields) for every
character in the font. The first word contains the bit count from the
start of a row to the bit information for the character. The second word
contains the bit count of the character. For the two characters in our
example it look like this:
charLoc: 0,9 9,5
The first character begins zero bits from the beginning of the data row and
is nine pixels wide. The second charcter begins 9 bits after the start of
the data row and is five pixels wide. This is the definition for all seven
rows of our characters.
Another problem is getting from one charData row to the next. The field
MODULO from the Textfont structure is used to do this. The length, in
bytes, of the data row is stored here. To get yor next row, add this value
to the current address of the data row.
The data field CharData contains only the basic information for the current
character. So, to separate the characters on the screen, we need to insert
some space between them. The field charSpace contains the real character
width, in pixels. For example:
charSpace: 11,7
The first character is eleven pixels wide and the second is seven.
There is one last problem, charSpace sets the actual character width. For
the first character in our example, this is eleven pixels.
PAGE 235
-----------------------------------------------------------------------------
...........
...........
...........
...........
...........
...........
...........
This is a problem because the character itself is only 9 pixels wide.
So the position at which this field should begin displaying the character
is still unknown. The block, charKern contains, for every character, a
word that defines, in bits, the distancee from the left edge of the field
where the character should be displayed. Again an example:
charKern: 1,2
This displays our characters on screen like this:
.....*..... ..****.
....*.*.... ..*...*
...*...*... ..*...*
..*.....*.. ..****.
.*********. ..*...*
.*.......*. ..*...*
.*.......*. ..****.
Space = 11 Space = 7
Kern = 1 Kern = 2
Width = 9 Width = 5
--------------------------------------------
5.5.1 READING THE FONT GENERATOR.
By using the information provided above, we can access an existing font
and read it. You can also get the data for a specific character and read
it.
The address of the TextFont structure for a font that is currently open
is found in the RastPort.
font& = PEEKL(WINDOW(8)+52)
You will find the required pointer to the memory block there (see section
5.1):
PAGE 236
-----------------------------------------------------------------------------
Here is the font reader program:
'##########################################
'#
'# Section: 5.5.1
'# Program: Font Readerr
'# Date : 04/11/87
'# Author : tob
'# Version: 1.0
'#
'###########################################
' Reads the currently active font and displays the
' decoded information in different sized variations.
PRINT "Searching for .bmap files...."
'GRAPHICS library
DECLARE FUNCTION OpenFont& LIBRARY
'SetFont()
'CloseFont()
LIBRARY "graphics.library"
init: '* Variables
DIM SHARED char$(256)
g% = 12 'Box size
CLS
FOR demo% = 32 TO 255
Matrix demo%
CLS
TopazON
PRINT "Character: ASCII ";demo%;" = ";CHR$(demo%)
FOR show% = 1 TO height%
LOCATE show%+2,1
PRINT char$(show%)
FOR ex% = 1 TO LEN(char$(show%))
z$ = MID$(char$(show%),ex%,1)
IF z$ = "*" THEN
kolor% = 2
ELSEIF z$ = "." THEN
kolor% = 1
ELSEIF z$ = "," THEN
kolo% = 3
END IF
LINE (300+ex%*g%,show%*g%)-(300+ex%*g%+g%,show%
*g%+g%),kolor%,bf
LINE (500+ex%*2,show%*2)-(500+ex%*2+2,show%*2+2),
kolor%,bf
NEXT ex%
PAGE 237
-----------------------------------------------------------------------------
NEXT show%
TopazOFF
NEXT demo%
END
SUB Matrix(code%) STATIC
SHARED height%
f.1% =0
f.2% =0
font% =PEEKL(WINDOW(8)+52)
charData& =PEEKL(font&+34)
charLoc& =PEEKL(font&+40)
charSpace& =PEEKL(font&+44)
charKern& =PEEKL(font&+48)
modulo% =PEEKW(font&+38)
IF charSpace& = 0 THEN f.1% = 1
IF charKern& = 0 THEN f.2% = 1
height% = PEEKW(font&+20)
loASCII = PEEK(font&+32)
hiASCII = PEEK(font&+33)
IF code%<loASCII% OR code%>hiASCII THEN
PRINT "ASCII code ";code%;" not in font"
END IF
'Decoding information.
offset% = code% - loASCII%
offset.bit&= PEEKW(charLoc&+4*offset%)
offset.byte%= INT(offset.bit&/8)
offset.bit% = offset.bit& - (8*offset.byte%)
char.width% = PEEKW(charLoc&+4*offset%+2)
IF f.1% = 0 THEN
char.space% = PEEKW(charSpace&+2*offset%)
END IF
IF f.2% = 0 THEN
char.kern% = PEEKW(charKern&+2*offset%)
END IF
'Read data
FOR loop1% = 1 TO height%
char$(loop1%) = ""
IF f.2% = 0 THEN
IF char.kern%>0 THEN
char$(loop1%)=STRING$(char.kern%,",")
END IF
END IF
linedata& = PEEK(charData+offset.byte%)
counter% = 7-offset.bit%
FOR loop2% = 1 TO char.width%
IF (linedata& AND 2^counter%)<>0 THEN
linedata& = linedata& - 2^counter%
PAGE 238
-----------------------------------------------------------------------------
char$(loop1%) = char$(loop1%)+"*"
ELSE
char$(loop1%) = char$(loop1%)+"."
END IF
counter% = counter% - 1
IF counter% < 0 THEN
offset.long% = offset.long%+1
linedata& = PEEK(charData&+offset.byte%+
offset.long%)
counter% = 7
END IF
NEXT loop2%
offset.long% = 0
charData& = charData&+modulo%
IF f.2% = 0 THEN
char.diff% = char.space%-char.width%-char.kern%
ELSEIF f.2% = 0 THEN
char.diff% = char.space%-char.width%
END IF
IF char.diff%>0 THEN
char$(loop1%)=char$(loop1%)+STRING$(char.diff%,",")
END IF
NEXT loop1%
END SUB
SUB TopazOn STATIC
SHARED font&,font.old&
font$ = "topaz.font"+CHR$(0)
textAttr&(0) = SADD(font$)
font.old& = PEEKL(WINDOW(8)+52)
font& = OpenFont&(VARPTR(textAttr&(0)))
CALL SetFont(WINDOW(8),font&)
END SUB
SUB TopazOFF STATIC
SHARED font&,font.old&
CALL CloseFont(font&)
CALL SetFont(WINDOW(8),font.old&)
END SUB
This program reads the currently active font. In most cases, this is one of
the two ROM fonts. To see something really interesting first load one of
the disk fonts like sapphire.
All the possible characters of the font are represented on the screen in
three ways: 1.) using "*" and ".", 2.) as large graphics, 3.) as small
graphics.
The graphics use three different colours. The data area define by charData
is white and all the set pixels are black. The additional pixels defined
by charSpace and CharKern are displayed in Orange.
PAGE 239
-----------------------------------------------------------------------------
However, proportional fonts will not display any orange because they do not
use charSpace and charKern.
The following is information about the program:
The heart of the program is the SUB matrix. This routine handles the
difficult task of reading the font but can also be used for other purposes.
Here is the call:
Matrix ascii.code%
ascii.code%: ASCII code of the character (0-255)
or:
Matrix CINT(ASC(z$))
z$: the desired character.
In addition, there are the SUB programs TopazOn and TopazOff, which switch
the currently active system font on and off. By using them, you are able to
display comments between the font data that are independant of the active
font being read and displayed.
An explanation of how the SUB Matrix functions is found in section 5.5
--------------------------------------------
5.5.2 BIG TEXT: ENLARGING TEXT.
This application demonstrates the adaptability of the read routine Matrix,
from our previous example. Matrix helps the SUB BigText create text of any
desired size on the screen.
This is the call:
BigText text$,sixe%,kolor%
text$: Text to display.
size%: Enlargin factor (1-...)
kolor%: Text color.
PAGE 240
-----------------------------------------------------------------------------
'#####################################
'#
'# Section: 5.5.2
'# Program: Enlarge text.
'# Date : 04/11/87
'# Author : tob
'# Version: 1.0
'#
'#####################################
' Enlarges any desired text. The text is enlarged in the
' style of the currently active font.
init:
'* Variables
DIM SHARED char$(256)
BigText "Hello",15,2
BigText "Commodore AMIGA",4,3
LOCATE 3,1
BigText "small",1,1
BigText "larger",2,1
BigText "Larger Yet!",3,1
BigText "GIGANTIC!",8,3
END
SUB BigText(text$,size%,kolor%) STATIC
SHARED height%,char.kern%,char.width%
SHARED char.space%
o.xo% = 0
z.x% = PEEKW(WINDOW(8)+58)
z.y% = PEEKW(WINDOW(8)+58)
y% = CSRLIN*z.y%
x% = POS(0)*z.x%
FOR loop1% = 1 TO LEN(text$)
z$ = MID$(text$,loop1%,1)
Matrix CINT(ASC(z$))
o.xo% = o.xo% + char.kern%*size%
FOR loop2% = 1 TO height%
FOR loop3% = 1 TO LEN(char$(loop2%))
m$ = MID$(char$(loop2%),loop3%,1)
IF m$ = "" THEN
o.x% = x%+o.xo%+loop3%*size%
o.y% = y%+loop2%*size%
LINE (o.x%,o.y%)-(o.x%+size%,o.y%+size%),
kolor%,bf
END IF
NEXT loop3%
NEXT loop2%
rest% = char.space%-char.width%-char.kern%
IF rest% < 0 THEN rest% = 0
o.xo% = o.xo%+char.width%*size%+rest%*size%
NEXT loop1%
PRINT
END SUB
PAGE 241
-----------------------------------------------------------------------------
SUB Matrix(code%) STATIC
SHARED height%, char.kern%, char.width%
SHARED char.space%
f.1% =0
f.2% =0
font% =PEEKL(WINDOW(8)+52)
charData& =PEEKL(font&+34)
charLoc& =PEEKL(font&+40)
charSpace& =PEEKL(font&+44)
charKern& =PEEKL(font&+48)
modulo% =PEEKW(font&+38)
IF charSpace& = 0 THEN f.1% = 1
IF charKern& = 0 THEN f.2% = 1
height% = PEEKW(font&+20)
loASCII = PEEK(font&+32)
hiASCII = PEEK(font&+33)
IF code%<loASCII% OR code%>hiASCII THEN
PRINT "ASCII code ";code%;" not in font"
END IF
'Decoding information.
offset% = code% - loASCII%
offset.bit&= PEEKW(charLoc&+4*offset%)
offset.byte%= INT(offset.bit&/8)
offset.bit% = offset.bit& - (8*offset.byte%)
char.width% = PEEKW(charLoc&+4*offset%+2)
z.b% = char.width%
IF f.1% = 0 THEN
char.space% = PEEKW(charSpace&+2*offset%)
z.b% = char.space%
END IF
IF f.2% = 0 THEN
char.kern% = PEEKW(charKern&+2*offset%)
END IF
'Read data
FOR loop1% = 1 TO height%
char$(loop1%) = ""
IF f.2% = 0 THEN
IF char.kern%>0 THEN
char$(loop1%)=STRING$(char.kern%,",")
END IF
END IF
linedata& = PEEK(charData+offset.byte%)
counter% = 7-offset.bit%
FOR loop2% = 1 TO char.width%
IF (linedata& AND 2^counter%)<>0 THEN
linedata& = linedata& - 2^counter%
char$(loop1%) = char$(loop1%)+"*"
ELSE
PAGE 242
-----------------------------------------------------------------------------
char$(loop1%) = char$(loop1%)+"."
END IF
counter% = counter% - 1
IF counter% < 0 THEN
offset.long% = offset.long%+1
linedata& = PEEK(charData&+offset.byte%+
offset.long%)
counter% = 7
END IF
NEXT loop2%
offset.long% = 0
charData& = charData&+modulo%
IF f.2% = 0 THEN
char.diff% = char.space%-char.width%-char.kern%
ELSEIF f.2% = 0 THEN
char.diff% = char.space%-char.width%
END IF
IF char.diff%>0 THEN
char$(loop1%)=char$(loop1%)+STRING$(char.diff%,",")
END IF
NEXT loop1%
END SUB
The matrix routine had to be changed slightly so that BigText could
position the text properly. In order to do this, we added a few more
parameters to the SHARED assignment at the beginning of the SUB.
--------------------------------------------
5.5.3 A FIXED WIDTH FONT GENERATOR.
Now that you are more comfortable with the pointers and contents of a font,
we will proceed to our main project, a character generator.
You have seen how difficult it is to define and manage a proportional font.
Because of this, our first character generator is a fixed width generator
which creates characters with identical widths.
To further simplify this process, our characters will have a set size of
8*8 pixels like the ROM font "topaz 8". Since this size has a one byte
offset, it's easy to store and handle the character data in charData.
Before we discuss the details of the program, here is the program listing:
PAGE 243
-----------------------------------------------------------------------------
'############################################
'#
'# Section: 5.5.3
'# Program: Fixed-width font generator.
'# Date : 04/12/87
'# Author : tob
'# Version: 1.0
'#
'##############################################
' This program makes possible the creation of a
' different font. Every character has a set size.
' of 8*8 pixels. Each character can be freely defined
' as required. All undefined characters will default to the
' standard ROM font (topaz 8). Unavailable characters will be
' indicated by the 'unprintable character' symbol.
PRINT "Searching for .bmap file ......"
'GRAPHICS-library
DECLARE FUNCTION OpenFont& LIBRARY
'CloseFont()
'SetFont()
'AddFont()
'EXEC-library
DECLARE FUNCTION AllocMem& LIBRARY
'FreeMem()
'CopyMem()
LIBRARY "graphics.library"
LIBRARY "exec.library"
init:
CLS
'* Generate character set
'* Call :
'* MakePrgFont "name",asciiLo%,asciiHi%
MakePrgFont "tobi",22,200
MakePrgFont "ralfi",60,122
'* Call:
'* ActivateFont "name"
ActivateFont "tobi"
'* Define new font.
'* Call:
'* NewD "char",row%,"definition"
'* row%: 0....7 definition: *=set pixel
NewD "A",0,"......*."
NewD "A",1,".....**."
NewD "A",2,"....***."
NewD "A",3,"...*.**."
PAGE 244
-----------------------------------------------------------------------------
NewD "A",4,"..*****."
NewD "A",5,".*....*."
NewD "A",6,"***..***"
NewD "A",7,""
ActivateFont "ralfi"
'* Second character using byte value method (faster)
NewB "@",0,126
NewB "@",1,129
NewB "@",2,157
NewB "@",3,161
NewB "@",4,161
NewB "@",5,157
NewB "@",6,129
NewB "@",7,126
'* Sample text
ActivateFont "tobi"
PRINT "@ 1989 Abacus (Alliance) - Amiga Graphics Inside &
out "
PRINT " ^ ^ "
ActivateFont "ralfi"
PRINT "@ 1989 Abacus (Alliance) - Amiga Graphics Inside
& out "
PRINT "^"
'* Delete font
'* Call:
'* DeleteFont "name"
DeleteFont "tobi"
DeleteFont "ralfi"
END
SUB ActivateFont(z.n$) STATIC
z.name$ = UCASE$(z.n$+".font"+CHR$(0))
t&(0) = SADD(z.name$)
t&(1) = 8*2^16
font& = OpenFont&(VARPTR(t&(0)))
IF font& = 0 THEN BEEP: EXIT SUB
CALL CloseFont(font&)
CALL SetFont(WINDOW(8),font&)
END SUB
SUB NewB(char$,row%,value%) STATIC
n.font& = PEEKL(WINDOW(8)+52)
n.data& = PEEKL(n.font&+34)
n.ascii& = ASC(char$)
n.lo% = PEEK(n.font&+32)
n.hi% = PEEK(n.font&+33)
n.modulo% = PEEKW(n.font&+38)
n.offset% = (n.ascii%-n.lo%)+row%*n.modulo%
n.data% = 0
IF n.ascii%<n.lo% OR n.ascii%>n.hi% THEN
PAGE 245
-----------------------------------------------------------------------------
PRINT "Character not in font!"
ERROR 255
END IF
POKE n.data&+n.offset%,value%
END SUB
SUB NewD(char$,row%,bit$) STATIC
n.font& = PEEKL(WINDOW(8)+52)
n.data& = PEEKL(n.font&+34)
n.ascii% = ASC(char$)
n.lo% = PEEK(n.font&+32)
n.hi% = PEEK(n.font&+33)
n.modulo% = PEEKW(n.font&+38)
n.offset% = (n.ascii%-n.lo%)+row%*n.modulo%
n.data% = 0
IF n.ascii%<n.lo% OR n.ascii%>n.hi% THEN
PRINT "Character not in font!"
ERROR 255
END IF
'* 8 bit alignment
IF LEN(bit$)<>8 THEN
IF LEN(bit$)>8 THEN bit$ = LEFT$(bit$,8)
IF LEN(bit$)<8 THEN bit$ = bit$+space$(8-LEN(bit$))
END IF
'* Write data in chardata.
FOR loop1%=7 TO 0 STEP -1
n.check$ = MID$(bit$,8-loop1%,1)
IF n.check$ = "*" THEN
n.data% = n.data%+2^loop1%
END IF
NEXT loop1%
POKE n.data&+n.offset%,n.data%
END SUB
SUB DeleteFont (z.n$) STATIC
z.name$ = UCASE$(z.n$+".font"+CHR$(0))
t&(0) = SADD(z.name$)
t&(1) = 8*2^16
font& = OpenFont&(VARPTR(t&(0)))
IF font&= 0 THEN ERROR 255
z.size& = PEEKL(font&-4)
IF z.size&<100 OR z.size&>4000 THEN ERROR 255
'* Remove from system list.
z.1& = PEEKL(font&)
z.2& = PEEKL(font&+4)
POKEL z.1&+4,z.2&
POKEL z.2&,z.1&
'* Release RAM
PAGE 246
-----------------------------------------------------------------------------
font& = font& - 4
CALL FreeMem(font&,z.size&)
'* Load standard font
standard$ = "topaz.font"+CHR$(0)
t&(0) = SADD(standard$)
font& = OpenFont&(VARPTR(t&(0)))
IF font& = 0 THEN ERROR 255
CALL SetFont(WINDOW(8),font&)
END SUB
SUB MakePrgFont(z.n$,ascii.lo%,ascii.hi%) STATIC
z.name$ = UCASE$(z.n$+".font"+CHR$(0))
z.count% = ascii.hi% - ascii.lo%=2
z.modulo% = z.count%
z.size& = z.count%*8+z.count%*4+110
z.offset% = ascii.lo%-32
z.begin% = 0
mem.opt& = 2^0+2^16
z.add& = AllocMem(z.size&,mem.opt&)
IF z.add& = 0 THEN ERROR 7
POKEL z.add&,z.size&
z.add& = z.add& + 4
z.data& = z.add& + 100
z.loc& = z.data&+z.count%*8
z.name& = z.add&+65
POKEL z.add&+10,z.name&
POKEW z.add&+18,z.size&-4
POKEW z.add&+20,8
POKE z.add&+23,64
POKEW z.add&+24,8
POKEW z.add&+26,6
POKE z.add&+32,ascii.lo%
POKE z.add&+33,ascii.hi%
POKEL z.add&+34,z.data&
POKEW z.add&+38,z.modulo%
POKEL z.add&+40,z.loc&
'* Fill Name field.
FOR loop1% = 1 TO LEN(z.name$)
POKE z.name$+loop1%-1,ASC(MID$(z.name$,loop1%,1))
NEXT loop1%
'* charLoc field
FOR loop1% = 0 TO z.count%-1
POKEW z.loc&+(4*loop1%)+0,loop1%*8
POKEW z.loc&+(4*loop1%)+2,8
NEXT loop1%
'* charData field.
sample$ = "topaz.font"+CHR$(0)
t&(0) = SADD(sample$)
PAGE 247
-----------------------------------------------------------------------------
t&(1) = 8*2^16
sample& = OpenFont&(VARPTR(t&(0)))
IF sample& = 0 THEN
PRINT "ROM-fonts weg???!"
ERROR 255
END IF
s.char& = PEEKL(sample&+34)
s.modulo% = PEEKW(sample&+38)
CALL CloseFont(sample&)
IF z.offset%<0 THEN
z.count% = z.count%+z.offset%
z.begin% = ABS(z.offset%)
z.offset% = 0
END IF
FOR loop1% = 0 TO 7
CALL CopyMem(s.char&+z.offset%+loop1%*s.modulo%, z.data&+
z.begin%+loop1%*z.modulo%,z.count%-1)
NEXT loop1%
'* Unprintable character.
POKE z.data&+z.modulo%-1+0*z.modulo%,224
POKE z.data&+z.modulo%-1+1*z.modulo%,64
POKE z.data&+z.modulo%-1+2*z.modulo%,64
POKE z.data&+z.modulo%-1+3*z.modulo%,64
POKE z.data&+z.modulo%-1+4*z.modulo%,73
POKE z.data&+z.modulo%-1+5*z.modulo%,73
POKE z.data&+z.modulo%-1+6*z.modulo%,77
POKE z.data&+z.modulo%-1+7*z.modulo%,74
'* Link
CALL AddFont(z.add&)
t&(0) = SADD(z.name$)
font.new& = OpenFont&(VARPTR(t&(0)))
IF font.new& = 0 THEN ERROR 255
CALL SetFont(WINDOW(8),font.new&)
END SUB
Altogether this program provides you with five SUB programs:
* MakePrgFont
* DeleteFont
* NewD
* NewB
* ActivateFont
MakePrgFont:
-----------
This SUB program allows you to create a completely new font which carries
the name assigned by you. Here is the call:
MakePrgFont name$,lo%,hi%
name$ : Name of new font.
lo% : ASCII value of first character
hi% : ASCII value of last character.
PAGE 248
-----------------------------------------------------------------------------
You determine the number of characters in your font. Every value has
an ASCII character that can be determined using the ASC function. Select
the low and high limits.
LINE INPUT "Character ";z$
PRINT ASC(z$)
The codes 0 TO 255 are available.
After the font is prepared, it contains no character definitions. Basically,
it is 'empty'; all the current characters equal nothing. Because of this we
will fill the new font with the data from the ROM font topaz 8.
After this call the new font is ready for your commands. All the characters
within your ASCII limits will be displayed with 'topaz8' characters.
Any character outside these limits will be displayed as an 'unprintable
character' with the small TW character.
Actviate Font:
-------------
This SUB program is useless to you if you only want to work with a single
font. However, if you wish to work with many fonts with different names,
you can select any of them with this command.
ActivateFont name$
name$ : The name of a previously generated font with MakePrgFont.
NewD:
----
Our goal was to define our own characters. This is accomplished with NewD.
Each character of our font is 8 pixels wide and 8 pixels high. By using
NewD, we can define any one of the eight rows of any character.
NewD char$,nr%,bit$
char$ : The character that you want to define.
nr% : The row of the character (0-7)
bit$ : The new data row (*=set pixels, "." unused pixels)
NOTE: NewD defines a character from the last generated (or active) font.
Obviously the character must exist in the font in order to be
redefined.
PAGE 249
-----------------------------------------------------------------------------
NewB
----
This is a variation of the NewD. When using NewD the character data for the
new character is displayed as astericks and points in binary form. This
binary data must first be converted to decimal. However, if you are
familiar with the binary decimal conversion, you can use the decimal values
directly. In order to do this, NewB is used.
NewB char$,nr%,value%
char$,nr% : Same as with NewD
value% : Decimal value for row (0 to 255).
DeleteFont
----------
When you no longer need one of your open fonts, you must close it again.
This is accomplished with the command:
DeleteFont name$
name$ : Name of the font opened using MakePrgFont.
At the end of your program you must close all of the fonts that were opened
using MakePrgFont. This returns the assigned memory to the system.
Those of you who want or need more information of making your own fonts
will fint detailed explanations on the following pages.
MakePrgFont
-----------
We fill the TextFont structure (from section 5.5) with all the required
parameters. Then we initialise the field CharLoc with its required
parameters. Because the characters of the font have a standard width value
of 8 pixels, the offset value is a multiple of 8. The width value is always
equal to 8 (see section 5.5).
The charData field is supposed to be filled with the use defined characters.
Since we assume that not all the characters will be redefined, we fill the
font with the ROM font topaz 8. After opening topaz 8, we save the pointer
to it in the variable sample&. The MODULO is also read. Now we can close
topaz again because the charData is in ROM and cannot be lost.
Next we must initialise two varaibles z.offset% and z.begin%. Your font
wont always have the same contents as the ROM type. The number of the
character that the new font will later begin with is contained in the
z.offset%. The ROM font always starts with ASCII code 32. If the first
character in your font has a larger value, for example "A" (code = 65),
then z.offset% contains 65-32 = 33. The opposite is accomplished with
z.begin%. If the ASCII code of the first character in your new font is
smaller than 32, then z.begin% contains the difference between the new
values.
PAGE 250
-----------------------------------------------------------------------------
Now we can copy the ROM data to the RAM buffer. For this we use a function
of the exec.library:
CALL CopyMem(o.data&,z.data&,bytes&)
o.data&: Original data.
z.data&: Target data.
bytes& : Number of bytes to copy.
This routine was first made available in Kickstart Version 1.2. Users of
older versions must either revise these commands into PEEKS and POKES
or completely leave out the loop. Otherwise you have to define all the
characters of the new font before working with it.
After all the characters are copied, the shape of the unprintable character
is defined as a small "TW". Whenever a user requests a characte that doesnt
exist in the font, the "TW" character will appear. The data for this
unprintable character us stored after the data for all the other characters.
Now the new font is completely functional. To add this font to the system,
we use the function AddFont. From this point on, other programs can also
access your font (for example the NOTEPAD). Finally we use OpenFont& to
open the new font. The address font.new& must match the address z.add&.
Right now it is necessary to take a closer look at the beginning of the
TextFont structure. The message structure looks like this:
Data structure Message/exec/20 bytes.
Offset Type Description.
------- ------- -------------------------------------------------
+000 Long Pointer to the next font.
+004 Long Pointer to the previous font.
+008 Byte Node Type.
+009 Byte Priority.
+010 Long Pointer to the name of the font.
+014 Long Pointer to ReplyPort.
+018 Word Length of Message.
Before we call the AddFont routine, we must store the name field and length
of the message, which equals the length of the font. After AddFont, the
rest of the pointers are initialised, which means that the first two
pointers point at different fonts.
This step is very important when you try to delete your font from the
system again. This will be explained further in DeleteFont.
PAGE 251
-----------------------------------------------------------------------------
ActivateFont
------------
Here we search for the font with the requested name. This SUB can be only
used to look for fonts that are created with MakePrgFont. The reason for
this is that the font is only opened for a short time, in order to receive
all the necessary pointers, and then closed again. We do not have to keep
it open because it has already been opened with MakePrgFont.
SetFont
-------
This SUB program activates the font.
NewD, NewB
----------
We read all the required font data from the RastPort. NewD converts the bit
definitions into a decimal number and therefore, is faster. The values are
poked to the locations set by your parameters.
DeleteFont
----------
The name font is opened here also. Fonts must always be removed by whatever
opened them. ROM fonts are never removed and disk fonts are loaded and
handled by AmigaDOS. You are responsible for the cleanup of your own
fonts. When reserving the memory, MakePrgFont stored the length of the
font in the last 4 bytes before the font. We read out this value. Before
we delete the font with FreeMem, we must correct the Systemlist because
AddFont integrated our font with the SystemList. The required fields are
restored and our font evaporates.
Now we can release the RAM allocated for the font and return this memory
to the system. To avoid being left without a font, we activate the ROM
font again.
----------------------------------------------
5.5.4 A PROPORTIONAL FONT.
Now we will discuss the complex proportional font. It is almost impossible,
in this type of font, to redefine existing characters. Every time we
redefine one character, hundreds of bytes would have to be shifted one way
or the other to adjust for the new character size. A solution to this
problem is to provide a number for the maximum width of any single
character. The program then reserves enough memory for a font containing
characters of this size. Although this method isn't memory efficient, it
is the only practical solution.
Again, our character generator demonstrates it's user friendliness. You
can easily create characters without being required to use any complex
numbers and parameters. We use six SUB programs:
MakePrgFont
DeleteFont
NewB
NewD
ActivateFont
Set
PAGE 252
-----------------------------------------------------------------------------
You are already familiar with these names. The way these SUB programs work
is very similar to those in the fixed width character generator from the
previous chapter.
Again, you can create as many fonts as you like. To do this use the
following command:
MakePrgFont name$,lo%,hi%,width%,height%,base%
name$ : Name of font.
lo% : Lower ASCII limit (See chapter 5.5.3)
hi% : Upper ASCII limit.
width% : Maximum width in pixels.
height% : Uniform height in pixels.
base% : Baseline (height without underline).
NOTE:
----
Baseline must be at least one pixel smaller than height%, otherwise, while
using algorithmic managed fonts (special italic), the system buffer can be
overwritten.
After this call, the Amiga generates a font with the above parameters; no
other information is required. This font is exactly the opposite from those
enerated with the fixed width generator because it is empty with no
previoulsy defined characters. Now it is your responsibility to define each
character in the font.
Before you design a particular character using the familiar SUB programs
NewD and NewB, you must specify and individual size for this character.
This is accomplished by using the "set" command:
Set char$,spacing%,kerning%
char$ : The character for which this value applies.
spacing% : Width of character (cannot exceed the maximum width
of the font generated).
kerning% : Number of pixels to skip before the character you
actually define appears.
Additional information can be found in section 5.5
PAGE 253
-----------------------------------------------------------------------------
All the other SUB programs have similar functions to those in the fixed
width generator. However, they are not identical.
'############################################
'#
'# Section: 5.5.4
'# Program: Proportional font generator.
'# Date : 04/12/87
'# Author : tob
'# Version: 1.0
'#
'##############################################
' This program makes it possible to create differently named
' proportional fonts and every character can have its own
' individual width. Undefined characters will not have character
' data, and will appear only after being successfully defined.
PRINT "Searching for .bmap file ......"
'GRAPHICS-library
DECLARE FUNCTION OpenFont& LIBRARY
'CloseFont()
'SetFont()
'AddFont()
'EXEC-library
DECLARE FUNCTION AllocMem& LIBRARY
'FreeMem()
LIBRARY "graphics.library"
LIBRARY "exec.library"
init:
'* Generate fonts
MakePrgFont "tobi",32,65,9,10,7
'* Set format
'* Set "character$",space,kern
Set "@",20,3
NewD "@",0,"...***..."
NewD "@",1,"..*...*.."
NewD "@",2,"......*.."
NewD "@",3,".....*..."
NewD "@",4,"....*...."
NewD "@",5,"....*...."
NewD "@",6,"........."
NewD "@",7,"*********"
NewD "@",8,".*******."
NewD "@",9,"..*****.."
'Second character using byte method.
PAGE 254
-----------------------------------------------------------------------------
Set "A",11,1
NewB "A",0,8,126
NewB "A",1,8,129
NewB "A",2,8,157
NewB "A",3,8,161
NewB "A",4,8,161
NewB "A",5,8,157
NewB "A",6,8,129
NewB "A",7,8,126
'* Sample text
PRINT STRING$(40,"A")
PRINT STRING$(40,"@")
'* Delete font
'* Call:
'* DeleteFont "name"
DeleteFont "tobi"
END
SUB ActivateFont(z.n$) STATIC
z.name$ = UCASE$(z.n$+".font"+CHR$(0))
t&(0) = SADD(z.name$)
t&(1) = 8*2^16
font& = OpenFont&(VARPTR(t&(0)))
IF font& = 0 THEN BEEP: EXIT SUB
CALL CloseFont(font&)
CALL SetFont(WINDOW(8),font&)
END SUB
SUB Set(char$,spacing%,kerning%) STATIC
n.font& = PEEKL(WINDOW(8)+52)
n.space& = PEEKL(n.font&+44)
n.kern& = PEEKL(n.font&+48)
n.ascii% = ASC(char$)
n.lo% = PEEK(n.font&+32)
n.hi% = PEEK(n.font&+33)
n.number% = n.ascii% - n.lo%
IF n.ascii%<n.lo% OR n.ascii%>n.hi% THEN
EXIT SUB
END IF
POKEW n.space&+(2*n.number%),spacing%
POKEW n.kern&+(2*n.number%),kerning%
END SUB
SUB NewB(char$,row%,bits%,value%) STATIC
n.byte% = 0
n.bit% = 0
n.font& = PEEKL(WINDOW(8)+52)
n.data& = PEEKL(n.font&+34)
n.loc& = PEEKL(n.font&+40)
n.ascii& = ASC(char$)
n.lo% = PEEK(n.font&+32)
n.hi% = PEEK(n.font&+33)
n.modulo% = PEEKW(n.font&+38)
n.offset% = row%*n.modulo%
n.height% = PEEKW(n.font&+20)
PAGE 255
-----------------------------------------------------------------------------
n.number% = n.ascii%-n.lo%
n.width% = PEEKW(PEEKL(n.font&+40)+(4*n.number%)+2)
n.offset& = PEEKW(PEEKL(n.font&+40)+(4*n.number%))
n.byte% = INT(n.offset&/8)
n.bit% = 7-(n.offset&-(n.byte%*8))
IF n.ascii%<n.lo% OR n.ascii%>n.hi% THEN
EXIT SUB
END IF
IF bits%>n.width% THEN
bits% = n.width%
END IF
n.data& = n.data&+n.offset%
FOR loop1% = bits%-1 TO 0 STEP -1
IF (value% AND 2^loop1%)<>0 THEN
POKE n.data&+n.byte%,PEEK(n.data&+n.byte%) OR (2^n.bit%)
END IF
n.bit% = n.bit% - 1
IF n.bit% < 0 THEN
n.bit% = 7
n.byte% = n.byte% + 1
END IF
NEXT loop1%
POKEW n.loc&+(4*n.number%)+2,bits%
END SUB
SUB NewD(char$,row%,bit$) STATIC
bits% = LEN(bits$)
n.byte% = 0
n.bit% = 0
n.font& = PEEKL(WINDOW(8)+52)
n.data& = PEEKL(n.font&+34)
n.loc& = PEEKL(n.font&+40)
n.ascii% = ASC(char$)
n.lo% = PEEK(n.font&+32)
n.hi% = PEEK(n.font&+33)
n.modulo% = PEEKW(n.font&+38)
n.offset% = row%*n.modulo%
n.height% = PEEKW(n.font&+20)
n.number% = n.ascii%-n.lo%
n.width% = PEEKW(PEEKL(n.font&+40)+(4*n.number%)+2)
n.offset& = PEEKW(PEEKL(n.font&+40)+(4*n.number%))
n.byte% = INT(n.offset&/8)
n.bit% = 7-(n.offset&-(n.byte%*8))
IF n.ascii%<n.lo% OR n.ascii%>n.hi% THEN
EXIT SUB
END IF
IF bits% > n.width% THEN
bits% = n.width%
END IF
PAGE 256
-----------------------------------------------------------------------------
n.data& = n.data& + n.offset%
FOR loop1%=bits%-1 TO 0 STEP -1
c$ = MID$(bits$,bits%-loop1%,1)
IF c$ = "" THEN
POKE n.data&+n.byte%,PEEK(n.data&+n.byte%) OR (2^n.bit%)
END IF
n.bit% = n.bit% - 1
IF n.bit% < 0 THEN
n.bit% = 7
n.byte% = n.byte%+1
END IF
NEXT loop1%
POKEW n.loc&+(4*n.number%)+2,bits%
END SUB
SUB DeleteFont (z.n$) STATIC
z.name$ = UCASE$(z.n$+".font"+CHR$(0))
t&(0) = SADD(z.name$)
t&(1) = 8*2^16
font& = OpenFont&(VARPTR(t&(0)))
IF font&= 0 THEN ERROR 255
z.size& = PEEKL(font&-4)
IF z.size&<100 OR z.size&>40000& THEN ERROR 255
'* Remove from system list.
z.1& = PEEKL(font&)
z.2& = PEEKL(font&+4)
POKEL z.1&+4,z.2&
POKEL z.2&,z.1&
'* Release RAM
font& = font& - 4
CALL FreeMem(font&,z.size&)
'* Load standard font
standard$ = "topaz.font"+CHR$(0)
t&(0) = SADD(standard$)
font& = OpenFont&(VARPTR(t&(0)))
IF font& = 0 THEN ERROR 255
CALL SetFont(WINDOW(8),font&)
END SUB
SUB MakePrgFont(z.n$,ascii.lo%,ascii.hi%,z.maxX%,z.height%,
z.baseline%) STATIC
z.name$ = UCASE$(z.n$+".font"+CHR$(0))
z.number% = ascii.hi%-ascii.lo%+2
z.modulo% = (z.number%*z.maxX%+4)/8
IF (z.modulo% MOD 2) <> 0 THEN
z.modulo% = z.modulo%+1
END IF
PAGE 257
-----------------------------------------------------------------------------
z.size& = z.modulo%*z.height%+z.number%*8+110
IF z.baseline%>z.height% THEN
z.baseline% = z.height%-1
END IF
mem.opt& = 2+0+2^16
z.add& = AllocMem(z.size&,mem.opt&)
IF z.add& = 0 THEN ERROR 7
POKEL z.add&,z.size&
z.add& = z.add&+4
z.data& = z.add&+100
z.loc& = z.data&+z.modulo%*z.height%
IF z.loc&/2<>INT(z.loc&/2) THEN
z.loc& = z.loc&+1
END IF
z.kern& = z.loc&+4*z.number%
z.space& = z.kern&+2*z.number%
z.name& = z.add&+65
POKEL z.add&+10,z.name&
POKEW z.add&+18,z.size&-4
POKEW z.add&+20,z.height%
POKE z.add&+23,64+32
POKEW z.add&+24,z.maxX%
POKEW z.add&+26,z.baseline%
POKE z.add&+32,ascii.lo%
POKE z.add&+33,ascii.hi%
POKEL z.add&+34,z.data&
POKEW z.add&+38,z.modulo%
POKEL z.add&+40,z.loc&
POKEL z.add&+44,z.space&
POKEL z.add&+48,z.kern&
'* Fill Name Field.
FOR loop1%=1 TO LEN(z.name$)
POKE z.name&+loop1%-1,ASC(MID$(z.name$,loop1%,1))
NEXT loop1%
'* charLoc field
FOR loop1% = 0 TO z.number%-1
POKEW z.loc&+(4*loop1%)+0,loop1%*z.maxX%
POKEW z.loc&+(4*loop1%)+2,maxX%
NEXT loop1%
'* Link
CALL AddFont(z.add&)
t&(0) = SADD(z.name$)
font.new& = OpenFont&(VARPTR(t&(0)))
IF font.new& = 0 THEN ERROR 255
CALL SetFont(WINDOW(8),font.new&)
END SUB
PAGE 258
-----------------------------------------------------------------------------